package com.zjx.activiti.service.impl;

import com.zjx.activiti.mapper.HistoryMapper;
import com.zjx.activiti.mapper.RuntimeMapper;
import com.zjx.activiti.service.RuntimeInfoService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.RuntimeServiceImpl;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.ReadOnlyProcessDefinition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Auther: zhaojx
 * @Date: 2021/8/25 16:55
 */
@Slf4j
@Service
public class RuntimInfoServiceImpl implements RuntimeInfoService {
    @Autowired
    private RuntimeMapper runtimeMapper;
    @Autowired
    private HistoryMapper historyMapper;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;

    @Override
    public List<Map<String, Object>> myTasks(String userId) {
        return runtimeMapper.selectMyTasksToDo(userId);
    }

    @Override
    @Transactional
    public boolean rejected(String taskId, String rejectElemKey, String dealReason) {
        int res = 0;
        //1.历史表
        //判断是否结束
        Map<String, Object> endEvent = historyMapper.selectEndEventByTaskId(taskId);
        log.info("查询hi_taskinst结束事件的结果，{}", endEvent);
        List<Map<String, Object>> hiTask = historyMapper.selectHiTaskByTaskId(taskId);
        String ruExcutionId = (String) hiTask.get(0).get("EXECUTION_ID_");
        String _processId = (String) hiTask.get(0).get("PROC_INST_ID_");

        //2.运行表
        //判断是驳回到原点：运行表ru_task，act_ru_identitylink，ru_variable，ru_execution清除节点信息
        if ("S00000".equals(rejectElemKey)) {
            if (null == endEvent || endEvent.isEmpty()) {
                //删variables
                res = runtimeMapper.deleteRuVariable(taskId);
                log.info("删ru_variables结束，{}", res);

                //删除当前的任务
                //不能删除当前正在执行的任务，所以要先清除掉关联
                TaskEntity currentTaskEntity = (TaskEntity) taskService.createTaskQuery()
                        .processInstanceId(_processId).singleResult();
                currentTaskEntity.setExecutionId(null);
                taskService.saveTask(currentTaskEntity);
                taskService.deleteTask(currentTaskEntity.getId(), true);
                log.info("删ru_task结束，{}", currentTaskEntity);

                //删execution
                res = runtimeMapper.deleteRuExecution(taskId);
                log.info("删ru_execution结束，{}", res);

                //删identitylink
                res = runtimeMapper.deleteRuIdentity(taskId);
                log.info("删ru_identitylink结束，{}", res);

            } else {
                //结束了，act_hi_actinst删掉结束event
                res = historyMapper.deleteHiEndEvent(taskId);
                log.info("删掉hi_actinst中endEvent结束，{}", res);
            }
        } else if ("end".equals(rejectElemKey)) {
            //驳回到终点
            ActivityImpl activity = findActivitiImpl(taskId, "end");
            if (Objects.nonNull(activity)) {
                jumpEndActivity(ruExcutionId, activity.getId(), dealReason);
            } else {
                return false;
            }
        } else {
            //判断是驳回到节点：运行表ru_task，ru_execution更改节点信息
            jumpEndActivity(ruExcutionId, rejectElemKey, dealReason);
        }
        return true;
    }

    /**
     * 根据任务ID和节点ID获取活动节点 <br>
     *
     * @param taskId     任务ID
     * @param activityId 活动节点ID <br>
     *                   如果为null或""，则默认查询当前活动节点 <br>
     *                   如果为"end"，则查询结束节点 <br>
     * @return
     * @throws Exception
     */
    @Override
    public ActivityImpl findActivitiImpl(String taskId, String activityId) {
        TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(
                taskId).singleResult();
        if (task == null) {
            return null;
        }
        // 取得流程定义
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(task.getProcessDefinitionId());

        if (processDefinition == null) {
            //throw new Exception("流程定义未找到!");
            return null;
        }

        // 获取当前活动节点ID
        if (StringUtils.isEmpty(activityId)) {
            activityId = task.getTaskDefinitionKey();
        }

        // 根据流程定义，获取该流程实例的结束节点
        if (activityId.toUpperCase().equals("END")) {
            for (ActivityImpl activityImpl : processDefinition.getActivities()) {
                List<PvmTransition> pvmTransitionList = activityImpl
                        .getOutgoingTransitions();
                if (pvmTransitionList.isEmpty()) {
                    return activityImpl;
                }
            }
        }

        // 根据节点ID，获取对应的活动节点
        ActivityImpl activityImpl = ((ProcessDefinitionImpl) processDefinition)
                .findActivity(activityId);
        return activityImpl;
    }

    @Override
    public void turnBackNew(String taskId) {
        try {
            Map<String, Object> variables;
            // 取得当前任务
            HistoricTaskInstance currTask = historyService.createHistoricTaskInstanceQuery().taskId(taskId)
                    .singleResult();
            // 取得流程实例
            ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(currTask.getProcessInstanceId()).singleResult();
            if (instance == null) {
                // 流程已经结束
            }
            variables = instance.getProcessVariables();
            // 取得流程定义
            ProcessDefinitionEntity definition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                    .getDeployedProcessDefinition(currTask.getProcessDefinitionId());
            if (definition == null) {
                // 流程定义未找到
                return;
            }
            // 取得上一步活动
            ActivityImpl currActivity = ((ProcessDefinitionImpl) definition)
                    .findActivity(currTask.getTaskDefinitionKey());
            List<PvmTransition> nextTransitionList = currActivity.getIncomingTransitions();
            // 清除当前活动的出口
            List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
            List<PvmTransition> pvmTransitionList = currActivity.getOutgoingTransitions();
            for (PvmTransition pvmTransition : pvmTransitionList) {
                oriPvmTransitionList.add(pvmTransition);
            }
            pvmTransitionList.clear();

            // 建立新出口
            List<TransitionImpl> newTransitions = new ArrayList<TransitionImpl>();
            for (PvmTransition nextTransition : nextTransitionList) {
                PvmActivity nextActivity = nextTransition.getSource();
                ActivityImpl nextActivityImpl = ((ProcessDefinitionImpl) definition).findActivity(nextActivity.getId());
                TransitionImpl newTransition = currActivity.createOutgoingTransition();
                newTransition.setDestination(nextActivityImpl);
                newTransitions.add(newTransition);
            }
            // 完成任务
            List<Task> tasks = taskService.createTaskQuery().processInstanceId(instance.getId())
                    .taskDefinitionKey(currTask.getTaskDefinitionKey()).list();
            for (Task task : tasks) {
                taskService.complete(task.getId(), variables);
                historyService.deleteHistoricTaskInstance(task.getId());
            }
            // 恢复方向
            for (TransitionImpl transitionImpl : newTransitions) {
                currActivity.getOutgoingTransitions().remove(transitionImpl);
            }
            for (PvmTransition pvmTransition : oriPvmTransitionList) {
                pvmTransitionList.add(pvmTransition);
            }

            // 成功
            log.info("驳回成功");
        } catch (Exception e) {
            // 异常
        }
    }


    /**
     * 根据ActivityId 查询出来想要活动Activity
     *
     * @param id
     * @return
     */
    public ActivityImpl queryTargetActivity(String id) {

        ReadOnlyProcessDefinition deployedProcessDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition("ziyouliu:1:4");
        List<ActivityImpl> activities = (List<ActivityImpl>) deployedProcessDefinition.getActivities();
        for (ActivityImpl activityImpl : activities) {
            if (activityImpl.getId().equals(id)) {
                return activityImpl;
            }
        }
        return null;
    }

    /**
     * 查询当前的活动节点
     */
    public ActivityImpl qureyCurrentTask(String processDefinitionId) {
        Execution execution = runtimeService.createExecutionQuery().processDefinitionId(processDefinitionId).singleResult();
        String activityId = execution.getActivityId();
        ActivityImpl currentActivity = queryTargetActivity(activityId);
        log.info(currentActivity.getId() + "" + currentActivity.getProperty("name"));
        return currentActivity;
    }


    /**
     * 驳回到指定节点
     *
     * @param executionId 当前节点
     * @param targetActId 目标节点
     * @param reason      驳回原因
     */
    public void jumpEndActivity(String executionId, String targetActId, String reason) {
        ((RuntimeServiceImpl) runtimeService).getCommandExecutor().execute(new Command<Object>() {
            public Object execute(CommandContext commandContext) {
                ExecutionEntity execution = commandContext.getExecutionEntityManager().findExecutionById(executionId);
                execution.destroyScope(reason);  //
                ProcessDefinitionImpl processDefinition = execution.getProcessDefinition();
                //目标节点
                ActivityImpl findActivity = processDefinition.findActivity(targetActId);
                execution.executeActivity(findActivity);
                return execution;
            }

        });
        log.info("自由跳转至节点：{}-----完成", targetActId);
    }


}
